package com.gitee.wsl.common.chart.sample.area

import android.graphics.*
import com.gitee.wsl.common.chart.ChartEnum
import com.gitee.wsl.common.chart.adapter.DataSource
import com.gitee.wsl.common.chart.adapter.SelectItemChartAdapter
import com.gitee.wsl.common.chart.listener.click.PlotPointPosition
import com.gitee.wsl.android.ui.ext.type.drawLine
import com.gitee.wsl.common.chart.model.DotInfo
import com.gitee.wsl.common.chart.render.background.axis.line.CategoryLineAxis
import com.gitee.wsl.common.chart.render.background.axis.line.DataLineAxis
import com.gitee.wsl.common.chart.render.shape.plot.renderDot
import com.gitee.wsl.common.chart.sample.area.adapter.AreaChartAdapter
import com.gitee.wsl.common.chart.sample.area.model.AreaData
import com.gitee.wsl.common.chart.sample.line.AbstractLineChart
import com.gitee.wsl.common.ui.draw.type.CurveLineStyle
import com.gitee.wsl.common.ui.draw.type.DotStyle
import com.gitee.wsl.common.ui.draw.type.GridDirection
import com.gitee.wsl.android.ui.ext.type.LineExt
import com.gitee.wsl.math.Math
import com.gitee.wsl.jvm.math.mul


import org.xclcharts.common.PointHelper
import timber.log.Timber


/**
 * @ClassName AreaChart
 * @Description 面积图基类
 * @author XiongChuanLiang<br/>
 *         (xcl_168@aliyun.com)
 */

class AreaChart(val adapter:AreaChartAdapter=AreaChartAdapter()):AbstractLineChart(adapter) ,
    SelectItemChartAdapter<AreaData> by adapter {

    // 画点分类的画笔
     val areaFillPaint: Paint by lazy {
         Paint().apply {
            style = Paint.Style.FILL
            isAntiAlias = true
            color = Color.rgb(73, 172, 72)
        }
    }

    // 数据源
     var dataSet by DataSource(adapter)

    // 透明度
    var areaAlpha = 100

    // path area
     val lstPathPoints= mutableListOf<PointF>()
     var pathArea = Path()
     //var bezierControls :List<PointF> = emptyList()

    // key
     //val mLstKey = mutableListOf<BaseLineData>()

    // line
     val lstPoints= mutableListOf<PointF>()

    // dots
     val lstDotInfo= mutableListOf<DotInfo>()

    // 平滑曲线
     var curveLineStyle = CurveLineStyle.BEZIERCURVE

    override fun getType(): ChartEnum.ChartType {
        return ChartEnum.ChartType.AREA
    }

    override fun categoryAxisDefaultSetting(categoryAxis: CategoryLineAxis) {
        super.categoryAxisDefaultSetting(categoryAxis)
        categoryAxis.tickMarksAlign = Paint.Align.CENTER
    }

    override fun dataAxisDefaultSetting(dataAxis: DataLineAxis) {
        super.dataAxisDefaultSetting(dataAxis)
        dataAxis.tickMarksAlign = Paint.Align.LEFT
    }

     private fun calcAllPoints(
        bd: AreaData, lstDotInfo: MutableList<DotInfo>,
        lstPoints: MutableList<PointF>, lstPathPoints: MutableList<PointF>,dataAxis: DataLineAxis,categoryAxis: CategoryLineAxis
    ): Boolean {
        // 数据源
        val chartValues = bd.linePointList
        var lineStartX: Float = bodyViewport.left
        var lineStartY: Float = bodyViewport.bottom
        var lineStopX = 0.0f
        var lineStopY = 0.0f
        val currLablesSteps: Float = getPlotScreenWidth() / (categoryAxis.dataSet.size - 1)
        val count = chartValues.size
        if (count <= 0) return false
        for (i in 0 until count) {
            val bv = chartValues[i]

            // 首尾为0,path不能闭合，改成 0.001都可以闭合?
            lineStopX = bodyViewport.left + Math.mul(i.toFloat(), currLablesSteps)
            lineStopY = getVPValPosition(bv,dataAxis)
            if (0 == i) {
                lineStartX = lineStopX
                lineStartY = lineStopY
                if (2 < count) {
                    if (bv.compareTo(dataAxis.axisMin) != 0) 
                        lstPathPoints.add(
                        PointF(
                            bodyViewport.left,
                            bodyViewport.bottom
                        )
                    )
                }
                lstPathPoints.add(PointF(lineStartX, lineStartY))
                lstPoints.add(PointF(lineStartX, lineStartY))
            }

            // path
            lstPathPoints.add(PointF(lineStopX, lineStopY))

            // line
            lstPoints.add(PointF(lineStopX, lineStopY))

            // dot
            lstDotInfo.add(DotInfo(bv, lineStopX, lineStopY))
            lineStartX = lineStopX
            lineStartY = lineStopY
        }
        if (count > 2) {
            lstPathPoints.add(PointF(lineStartX, lineStartY))
            if (chartValues[count - 1].compareTo(dataAxis.axisMin) != 0) {
                lstPathPoints.add(PointF(lineStartX, bodyViewport.bottom))
            }
        }
        return true
    }

    private fun drawBezierCurveLine(
        canvas: Canvas, bezierPath: Path,
        areaData: AreaData, lstPoints: List<PointF>
    ): Boolean {
        drawBezierCurveLine(canvas, areaData.dotLinePaint, bezierPath, lstPoints)
        return true
    }

     private fun drawBezierArea(
        canvas: Canvas, paintAreaFill: Paint,
        bezierPath1: Path, areaData: AreaData, lstPathPoints: List<PointF>
    ): Boolean {
        var bezierPath: Path = bezierPath1
        val count = lstPathPoints.size
        if (count < 3) return false // 没有或仅一个点就不需要了

        // 设置当前填充色
        paintAreaFill.color = areaData.areaFillColor

        // 仅两点
        if (count == 3) {
            bezierPath.moveTo(lstPathPoints[0].x, bodyViewport.bottom)
            bezierPath.lineTo(lstPathPoints[0].x, lstPathPoints[0].y)
            val ctl3 = PointHelper.percent(
                lstPathPoints[1], 0.5f,
                lstPathPoints[2], 0.8f
            )
            bezierPath.quadTo(ctl3.x, ctl3.y, lstPathPoints[2].x, lstPathPoints[2].y)

            // canvas.drawCircle(ctl3.x, ctl3.y, 10.f, paintAreaFill); //显示控制点
            bezierPath.lineTo(lstPathPoints[2].x, bodyViewport.bottom)
            bezierPath.close()
            if (areaData.applayGradient) {
                val linearGradient: LinearGradient
                if (areaData.gradientGridDirection == GridDirection.VERTICAL) {
                    val lineMaxY = getLineMaxMinY(Y_MAX, lstPathPoints)
                    linearGradient = LinearGradient(
                        0f,
                        0f,
                        0f,
                        bodyViewport.bottom - lineMaxY,  // 2 * h,
                        // plotArea.left,plotArea.bottom,
                        // lstPathPoints.get(count -1).x,lineMinY,
                        areaData.areaBeginColor,
                        areaData.areaEndColor,
                        areaData.gradientMode
                    )
                } else {
                    val lineMinY = getLineMaxMinY(Y_MIN, lstPathPoints)
                    linearGradient = LinearGradient(
                        bodyViewport.left,
                        bodyViewport.bottom, lstPathPoints[2].x,
                        lineMinY, areaData.areaBeginColor,
                        areaData.areaEndColor,
                        areaData.gradientMode
                    )
                }
                paintAreaFill.shader = linearGradient
            } else {
                paintAreaFill.shader = null
            }
            canvas.drawPath(bezierPath, paintAreaFill)
            bezierPath.reset()
            return true
        }

        // 透明度
        paintAreaFill.alpha = areaAlpha

        // start point
        bezierPath.moveTo(bodyViewport.left, bodyViewport.bottom)
        val axisMinValue: Float = bodyViewport.bottom
        for (i in 0 until count) {
            if (i < 3) continue

            // 连续两个值都为0,控制点有可能会显示在轴以下，则此种情况下，将其处理为直线
            if (lstPathPoints[i - 1].y >= axisMinValue && lstPathPoints[i].y >= axisMinValue) {
                // 如果最后两点为0时此处调用了两次，最后一次跳过不做处理,原因是数组的最后一个点的y值必定为0
                if (i == count - 1) {
                    continue
                }
                if (null == bezierPath) {
                    bezierPath = Path()
                    bezierPath.moveTo(
                        lstPathPoints[i - 2].x,
                        lstPathPoints[i - 2].y
                    )
                } else {
                    bezierPath.lineTo(
                        lstPathPoints[i - 2].x,
                        lstPathPoints[i - 2].y
                    )
                }
                // change by chenqiang
                if (lstPathPoints[i - 2].y >= axisMinValue) { //连续3个点为0
                    bezierPath.moveTo(
                        lstPathPoints[i - 1].x,
                        lstPathPoints[i - 1].y
                    )
                } else {
                    bezierControls=LineExt.curve3(
                        lstPathPoints[i - 2],
                        lstPathPoints[i - 1], lstPathPoints[i - 3],
                        lstPathPoints[i]
                    )
                    bezierPath.quadTo(
                        bezierControls.first.x, bezierControls.first.y,
                        lstPathPoints[i - 1].x, lstPathPoints[i - 1].y
                    )
                }
                bezierPath.close()
                if (areaData.applayGradient) {
                    var linearGradient: LinearGradient?
                    if (areaData.gradientGridDirection == GridDirection.VERTICAL) {
                        val lineMaxY = getLineMaxMinY(Y_MAX, lstPathPoints)
                        linearGradient = LinearGradient(
                            0f, 0f, 0f, lineMaxY,
                            areaData.areaBeginColor,
                            areaData.areaEndColor,
                            areaData.gradientMode
                        )
                    } else {
                        val lineMinY = getLineMaxMinY(Y_MIN, lstPathPoints)
                        linearGradient = LinearGradient(
                            bodyViewport.left,
                            bodyViewport.bottom,
                            lstPathPoints[i - 1].x, lineMinY,
                            areaData.areaBeginColor,
                            areaData.areaEndColor,
                            areaData.gradientMode
                        )
                    }
                    paintAreaFill.shader = linearGradient
                } else {
                    paintAreaFill.shader = null
                }
                canvas.drawPath(bezierPath, paintAreaFill)
                bezierPath.reset()
                bezierPath.moveTo(lstPathPoints[i].x, lstPathPoints[i].y)
                continue
            }
            bezierControls=LineExt.curve3(lstPathPoints[i - 2], lstPathPoints[i - 1], lstPathPoints[i - 3], lstPathPoints[i])

            // change by chenqiang
            calcBezierCurvePathAxisMinValue(bezierPath, lstPathPoints[i - 2], lstPathPoints[i - 1], bezierControls)
        }

        // 最后两点间的区域
        val stop = lstPathPoints[count - 1] // 通过calcAllPoints函数，stop的y值一定是0
        if (lstPathPoints[count - 2].y >= axisMinValue) { // 最后一点是0
            // change by chenqiang
            bezierControls=LineExt.curve3(lstPathPoints[count - 3], stop, lstPathPoints[count - 4], stop)
            calcBezierCurvePathAxisMinValue(bezierPath, lstPathPoints[count - 3], stop, bezierControls)
        } else {
            bezierControls=LineExt.curve3(lstPathPoints[count - 2], stop, lstPathPoints[count - 3], stop)
            // change by chenqiang
            calcBezierCurvePathAxisMinValue(bezierPath, lstPathPoints[count - 2], lstPathPoints[count - 1], bezierControls)
        }
        bezierPath.close()
        if (areaData.applayGradient) {
            val linearGradient: LinearGradient
            if (areaData.gradientGridDirection == GridDirection.VERTICAL) {
                val lineMaxY = getLineMaxMinY(Y_MAX, lstPathPoints)
                linearGradient = LinearGradient(
                    0f, 0f, 0f, lineMaxY,
                    areaData.areaBeginColor,
                    areaData.areaEndColor, areaData.gradientMode
                )
            } else {
                val lineMinY = getLineMaxMinY(Y_MIN, lstPathPoints)
                linearGradient = LinearGradient(
                    bodyViewport.left,
                    bodyViewport.bottom, stop.x, lineMinY,
                    areaData.areaBeginColor,
                    areaData.areaEndColor, areaData.gradientMode
                )
            }
            paintAreaFill.shader = linearGradient
        } else {
            paintAreaFill.shader = null
        }
        canvas.drawPath(bezierPath, paintAreaFill)
        bezierPath.reset()
        return true
    }

     private fun drawArea(
        canvas: Canvas, paintAreaFill: Paint,
        pathArea: Path, areaData: AreaData, lstPathPoints: List<PointF>
    ): Boolean {
        val count = lstPathPoints.size
        if (count < 3) return false // 没有或仅一个点就不需要了
        // 设置当前填充色
        paintAreaFill.color = areaData.areaFillColor
        if (areaData.applayGradient) {
            val linearGradient: LinearGradient
            if (areaData.gradientGridDirection == GridDirection.VERTICAL) {
                val lineMaxY = getLineMaxMinY(Y_MAX, lstPathPoints)
                linearGradient = LinearGradient(
                    0f, 0f, 0f, lineMaxY,
                    areaData.areaBeginColor,
                    areaData.areaEndColor, areaData.gradientMode
                )
            } else {
                val lineMinY = getLineMaxMinY(Y_MIN, lstPathPoints)
                linearGradient = LinearGradient(
                    bodyViewport.left,
                    bodyViewport.bottom, lstPathPoints[count - 1].x,
                    lineMinY, areaData.areaBeginColor,
                    areaData.areaEndColor, areaData.gradientMode
                )
            }
            paintAreaFill.shader = linearGradient
        } else {
            paintAreaFill.shader = null
        }
        // 透明度
        paintAreaFill.alpha = areaAlpha

        // 仅两点
        if (count == 3) {
            pathArea.moveTo(lstPathPoints[0].x, bodyViewport.bottom)
            pathArea.lineTo(lstPathPoints[0].x, lstPathPoints[0].y)
            pathArea.lineTo(lstPathPoints[1].x, lstPathPoints[1].y)
            pathArea.lineTo(lstPathPoints[2].x, lstPathPoints[2].y)
            pathArea.lineTo(lstPathPoints[2].x, bodyViewport.bottom)
            pathArea.close()
            // 绘制area
            canvas.drawPath(pathArea, paintAreaFill)
            pathArea.reset()
            return true
        }
        for (i in 0 until count) {
            val point = lstPathPoints[i]
            if (0 == i) {
                pathArea.moveTo(point.x, point.y)
            } else {
                pathArea.lineTo(point.x, point.y)
            }
        }
        pathArea.close()

        // 绘制area
        canvas.drawPath(pathArea, paintAreaFill)
        pathArea.reset()
        return true
    }

    private fun drawLine(
        canvas: Canvas, areaData: AreaData,
        lstPoints: List<PointF>
    ): Boolean {
        val count = lstPoints.size
        for (i in 0 until count) {
            if (0 == i) continue
            val pointStart = lstPoints[i - 1]
            val pointStop = lstPoints[i]
            canvas.drawLine(areaData.lineSpacingStyle, pointStart.x, pointStart.y, pointStop.x, pointStop.y, areaData.dotLinePaint)
        }
        return true
    }


    /**
     * 绘制区域
     *
     * @param bd
     * 数据序列
     * @param type
     * 绘制类型
     * @param alpha
     * 透明度
     */
    private fun drawDotAndLabel(
        canvas: Canvas, bd: AreaData, dataID: Int,
        lstDotInfo: List<DotInfo>
    ): Boolean {
        val itemAngle = bd.itemLabelRotateAngle
        val pLine = bd.plotLine
        if (pLine.dotStyle == DotStyle.HIDE && !bd.isLabelVisible) {
            return true
        }
        val pDot = pLine.plotDot
        val radius = pDot.dotRadius
        val count = lstDotInfo.size
        for (i in 0 until count) {
            val dotInfo = lstDotInfo[i]
            if (pLine.dotStyle != DotStyle.HIDE) {
                canvas.renderDot(pDot, dotInfo.x, dotInfo.y, pLine.dotPaint)
                savePointRecord(
                    dataID, i, dotInfo.x + moveX, dotInfo.y
                            + moveY, dotInfo.x - radius + moveX, dotInfo.y
                            - radius + moveY, dotInfo.x + radius + moveX,
                    dotInfo.y + radius + moveY
                )
            }

            // 显示批注形状
            drawAnchor(anchorSet, dataID, i, canvas, dotInfo.x, dotInfo.y, radius)
            if (bd.isLabelVisible) {
                bd.plotLabel.renderLabel(
                    canvas, pLine.dotLabelPaint,
                    getFormatterItemLabel(dotInfo.value), dotInfo.x,
                    dotInfo.y, itemAngle, bd.lineColor
                )
            }
        }
        adapter.isRecordSetInited = true
        return true
    }

     private fun getLineMaxMinY(type: Int, lstPathPoints: List<PointF>): Float {
        // 渲染高度
        var lineMaxY = 0.0f
        var lineMinY = 0.0f
        val count = lstPathPoints.size
        for (i in 0 until count) {
            if (Y_MAX == type) {
                if (lineMaxY < lstPathPoints[i].y) lineMaxY = lstPathPoints[i].y
            } else if (Y_MIN == type) {
                if (0 == i) {
                    lineMinY = lstPathPoints[0].y
                } else {
                    if (lineMinY > lstPathPoints[i].y) lineMinY = lstPathPoints[i].y
                }
            }
        }
        return if (Y_MAX == type) {
            lineMaxY
        } else { // if(Y_MIN == type){
            lineMinY
        }
    }

     private fun drawVerticalPlot(canvas: Canvas, dataAxis: DataLineAxis, categoryAxis: CategoryLineAxis): Boolean {
        
        //this.initPaint();

        // 透明度。其取值范围是0---255,数值越小，越透明，颜色上表现越淡
        // mPaintAreaFill.setAlpha( mAreaAlpha );

        // 开始处 X 轴 即分类轴
        val count = dataSet.size
        for (i in 0 until count) {
            val areaData = dataSet[i]
            calcAllPoints(areaData, lstDotInfo, lstPoints, lstPathPoints,dataAxis, categoryAxis)
            when (this.curveLineStyle) {
                CurveLineStyle.BEZIERCURVE -> {
                    drawBezierArea(canvas, areaFillPaint, pathArea, areaData, lstPathPoints)
                    drawBezierCurveLine(canvas, pathArea, areaData, lstPoints)
                }
                CurveLineStyle.BEELINE -> {
                    drawArea(canvas, areaFillPaint, pathArea, areaData, lstPathPoints)
                    drawLine(canvas, areaData, lstPoints)
                }
                else -> {
                    Timber.d( "未知的枚举类型.")
                    continue
                }
            }
            drawDotAndLabel(canvas, areaData, i, lstDotInfo)
            lstKey.add(areaData)
            lstDotInfo.clear()
            lstPoints.clear()
            lstPathPoints.clear()
        }
        return true
    }

    // ///////////////////////////////////////////
    override fun drawClipPlot(canvas: Canvas, dataAxis: DataLineAxis, categoryAxis: CategoryLineAxis) {
        if (drawVerticalPlot(canvas,dataAxis, categoryAxis)) {
            // 画横向定制线
            customLine?.let {
                it.setVerticalPlot(dataAxis, bodyViewport, getAxisScreenHeight())
                it.renderVerticalCustomlinesDataAxis(canvas)
            }
        }
    }

     fun savePointRecord(
        dataID: Int, childID: Int,
        x: Float, y: Float, left: Float, top: Float, right: Float, bottom: Float
    ) {
        if(adapter.isRecordSetInited) return
        val pRecord = PlotPointPosition()
        pRecord.savePlotDataID(dataID)
        pRecord.savePlotDataChildID(childID)
        pRecord.savePlotPosition(x, y)
        pRecord.savePlotRectF(left, top, right, bottom)
        //pRecord.extPointClickRange(clickRangeExtValue)
        adapter.addRecordItem(pRecord)
    }

    override fun drawClipLegend(canvas: Canvas) {
        //plotLegend.renderLineKey(canvas, mLstKey)
        //mLstKey.clear()
    }
    // //////////////////////////////////////////
    
    
    companion object{
         const val Y_MIN = 0
         const val Y_MAX = 1
    }
}